; 编译链接方法

;nasm -f elf -o kernel.o kernel.asm
;gcc -c -o main.o main.c
;ld -s -Ttext 0x30400  -o kernel.bin kernel.o main.o font.o lib.o


;常量定义
selectorKernelCs  equ 8

P_STACKBASE	equ	0
GSREG		equ	P_STACKBASE
FSREG		equ	GSREG		+ 4
ESREG		equ	FSREG		+ 4
DSREG		equ	ESREG		+ 4
EDIREG		equ	DSREG		+ 4
ESIREG		equ	EDIREG		+ 4
EBPREG		equ	ESIREG		+ 4
KERNELESPREG	equ	EBPREG		+ 4
EBXREG		equ	KERNELESPREG	+ 4
EDXREG		equ	EBXREG		+ 4
ECXREG		equ	EDXREG		+ 4
EAXREG		equ	ECXREG		+ 4
RETADR		equ	EAXREG		+ 4
EIPREG		equ	RETADR		+ 4
CSREG		equ	EIPREG		+ 4
EFLAGSREG	equ	CSREG		+ 4
ESPREG		equ	EFLAGSREG	+ 4
SSREG		equ	ESPREG		+ 4
P_STACKTOP	equ	SSREG		+ 4
P_LDT_SEL	equ	P_STACKTOP
P_LDT		equ	P_LDT_SEL	+ 4

TSS3_S_SP0	equ	4

; 以下选择子值必须与 protect.h 中保持一致!!!
SELECTOR_FLAT_C		equ		0x08	; LOADER 里面已经确定了的.
SELECTOR_TSS		equ		0x20	; TSS
SELECTOR_KERNEL_CS	equ		SELECTOR_FLAT_C


extern  main              ;引入c编写的主函数  main.c 中主函数
extern  initGdtAndIdt     ;初始化新的gdt 和idt

extern  gdtPtr            ;保存gdt 基地址和偏移地址 在main.c 中定义
extern  idtPtr            ;保存idt 基地址和偏移地址 在main.c 中定义
extern	exception_handler ;中断和异常处理程序

extern	p_proc_ready
extern	tss



[bits 32]
; 内核堆栈段定义
[section .bss]
stackSpace  resb   2*1024    ;2k
stackTop:                    ;栈顶

; 内核代码段
[section .text]	             ; 代码段
global _start	             ; 导出 _start
global init                  ;
global io_hlt                ; 导出 _io_hlt  这里前边不用加下滑线
global io_cli                ;
global io_sti                ;
global io_stihlt             ;
global io_in8                ;
global io_in16               ;
global io_in32               ;
global io_out8               ;
global io_out16              ;
global io_out32              ;
global io_load_eflags        ;
global io_store_eflags       ;

;中断和异常处理程序
global	divide_error
global	single_step_exception
global	nmi
global	breakpoint_exception
global	overflow
global	bounds_check
global	inval_opcode
global	copr_not_available
global	double_fault
global	copr_seg_overrun
global	inval_tss
global	segment_not_present
global	stack_exception
global	general_protection
global	page_fault
global	copr_error
global  exceptionUd2






; 跳到这里来的时候
_start:       
        mov esp ,stackTop ;从loader 中把堆栈切换到kernel 中
	sgdt [gdtPtr]  ;保存gdt 到全局变量 gdtPtr

	call initGdtAndIdt   ;初始化gdt
	lgdt [gdtPtr]  ;重新加载新的gdt
	lidt [idtPtr]  ;加载idt
	jmp selectorKernelCs:init ;切换到新的代码段上

init:
        call main      ;调用c 中主函数


;从ring0 切换到ring3
restart:
	mov	esp, [p_proc_ready]
	lldt	[esp + P_LDT_SEL] 
	lea	eax, [esp + P_STACKTOP]
	mov	dword [tss + TSS3_S_SP0], eax

	pop	gs
	pop	fs
	pop	es
	pop	ds
	popad

	add	esp, 4

	iretd


;人为产生测试异常
exceptionUd2:
         ;ud2
	 xor eax,eax
	 mov ax,SELECTOR_TSS
	 ltr ax
	 jmp restart


; void io_hlt() 停机函数,c 中没有功能实现hlt 指令
io_hlt: 
        hlt
        ret

;void io_cli()
io_cli:
        cli
	ret

;void io_sti()
io_sti:
        sti
	ret

;void io_stihlt()
io_stihlt:
        sti
	hlt
	ret

;int io_in8(int port)
io_in8:
       mov edx ,[esp+4] ;取port
       mov eax ,0       ;返回值清零
       in  al  ,dx
       ret

;int io_in16(int port)
io_in16:
       mov edx ,[esp+4] ;取port
       mov eax ,0       ;返回值清零
       in  ax  ,dx
       ret

;int io_in32(int port)
io_in32:
       mov edx ,[esp+4] ;取port
       mov eax ,0       ;返回值清零
       in  eax  ,dx
       ret

; void io_out8(int port,int data)
io_out8:
       mov edx,[esp+4]
       mov al ,[esp+8]
       out dx,al
       ret

; void io_out16(int port,int data)
io_out16:
       mov edx ,[esp+4]
       mov eax ,[esp+8]
       out dx,ax
       ret

; void io_out32(int port,int data)
io_out32:
       mov edx ,[esp+4]
       mov eax ,[esp+8]
       out dx,eax
       ret
;int io_load_eflags()
io_load_eflags:
       pushfd
       pop eax
       ret
;void io_store_eflags(int eflags)
io_store_eflags:
       mov  eax,[esp+4]
       push eax
       popfd
       ret

; 中断和异常 -- 异常
divide_error:
	push	0xFFFFFFFF	; no err code
	push	0		; vector_no	= 0
	jmp	exception
single_step_exception:
	push	0xFFFFFFFF	; no err code
	push	1		; vector_no	= 1
	jmp	exception
nmi:
	push	0xFFFFFFFF	; no err code
	push	2		; vector_no	= 2
	jmp	exception
breakpoint_exception:
	push	0xFFFFFFFF	; no err code
	push	3		; vector_no	= 3
	jmp	exception
overflow:
	push	0xFFFFFFFF	; no err code
	push	4		; vector_no	= 4
	jmp	exception
bounds_check:
	push	0xFFFFFFFF	; no err code
	push	5		; vector_no	= 5
	jmp	exception
inval_opcode:
	push	0xFFFFFFFF	; no err code
	push	6		; vector_no	= 6
	jmp	exception
copr_not_available:
	push	0xFFFFFFFF	; no err code
	push	7		; vector_no	= 7
	jmp	exception
double_fault:
	push	8		; vector_no	= 8
	jmp	exception
copr_seg_overrun:
	push	0xFFFFFFFF	; no err code
	push	9		; vector_no	= 9
	jmp	exception
inval_tss:
	push	10		; vector_no	= A
	jmp	exception
segment_not_present:
	push	11		; vector_no	= B
	jmp	exception
stack_exception:
	push	12		; vector_no	= C
	jmp	exception
general_protection:
	push	13		; vector_no	= D
	jmp	exception
page_fault:
	push	14		; vector_no	= E
	jmp	exception
copr_error:
	push	0xFFFFFFFF	; no err code
	push	16		; vector_no	= 10h
	jmp	exception

exception:
	call	exception_handler
	add	esp, 4*2	; 让栈顶指向 EIP，堆栈中从顶向下依次是：EIP、CS、EFLAGS
	hlt

;中断处理程序
align 16
hwint00:
       iretd